#include <stdio.h>

#include "public/errno.h"
#include "ymodem.h"
#include "utils/utils_crc16.h"

#define ENABLE_DEBUG    0
#include "debug.h"

static int packet_size(unsigned char code);
static int packet_parase(struct ymodem *ymodem, unsigned int *discard_len);
static void packet_discard(struct ymodem *ymodem, unsigned int discard_len);


static unsigned int str_to_u32(const char* str);

int ymodem_recv_process(struct ymodem *ymodem)
{
    int ret;
    int len;
    int code;
    char *file_size;
    unsigned int discard_len;
    unsigned char one_byte = 0;

    if (NULL == ymodem || NULL == ymodem->read || NULL == ymodem->write || NULL == ymodem->time_msec) {
        return -EINVAL;
    }

    /* 没有收到数据，且进入流程，且接收超时，则传输失败 */
    if (0 >= ymodem->read(&one_byte, 1)) {
        if (ymodem->stage != YMODEM_STAGE_NONE) {
            if (ymodem->time_msec() >= ymodem->timestart + ymodem->timeout) {
                /* 已超时，超时失败 */
                DEBUG("[YMODEM]: TIMEOUT\n");
                ret = -ETIMEDOUT;
                goto EXIT;
            }
            else {
                /* 未超时，继续等待 */
                return -EBUSY;
            }
        }
        /* 空闲状态，继续往下跑 */
    }
    /* 已经收到数据，则更新起始时间 */
    else {
        ymodem->timestart = ymodem->time_msec();
        /* 继续往下跑 */
    }

    switch (ymodem->stage) {
    case YMODEM_STAGE_NONE:
        ymodem->rd_len = 0;
        one_byte = YMODEM_CODE_REQ;
        ymodem->write((void *)&one_byte, 1);
        DEBUG("[YMODEM]: SEND REQ\n");
        ymodem->timestart = ymodem->time_msec();
        ymodem->stage = YMODEM_STAGE_ESTABLISHING;
        break;
    case YMODEM_STAGE_ESTABLISHING:
        if (ymodem->buffer == NULL) {
            DEBUG("[YMODEM]: NOBUFFER\n");
            ret = -ENOMEM;
            goto EXIT;
        }
        /* 读取数据 */
        ymodem->buffer[ymodem->rd_len] = one_byte;
        ymodem->rd_len += 1;
        len = ymodem->read(ymodem->buffer + ymodem->rd_len, PACKET_OVERHEAD + PACKET_1K_SIZE - ymodem->rd_len);
        ymodem->rd_len += len;

        code = packet_parase(ymodem, &discard_len);
        if (code < 0) {
            DEBUG("[YMODEM]: DISCARD: %d Bytes\n", discard_len);

            /* 删除已经处理的数据 */
            packet_discard(ymodem, discard_len);
        }
        else if (code > 0) {
            if (code == YMODEM_CODE_SOH || code == YMODEM_CODE_STX) {
                /* 握手成功 */
                one_byte = YMODEM_CODE_ACK;
                ymodem->write((void *)&one_byte, 1);
                DEBUG("[YMODEM]: SEND ACK\n");

                /* 保存文件名字 */
                memset(ymodem->file_name, '\0', FILE_NAME_LENGTH);
                strncpy(ymodem->file_name, (const char *)&ymodem->buffer[PACKET_HEADER], FILE_NAME_LENGTH - 1);

                /* 保存文件大小 */
                file_size = (char *)&ymodem->buffer[PACKET_HEADER + strlen((const char *)&ymodem->buffer[PACKET_HEADER]) + 1];
                ymodem->file_size = str_to_u32(file_size);

                DEBUG("[YMODEM]: file name: %s, size: %d\n", ymodem->file_name, ymodem->file_size);

                /* 处理数据 */
                if (ymodem->begin_packet_cb) {
                    ret = ymodem->begin_packet_cb(&ymodem->buffer[PACKET_HEADER], packet_size(code), ymodem);
                    if (ret < 0) {
                        goto EXIT;
                    }
                }

                /* 删除已经处理的数据 */
                packet_discard(ymodem, discard_len);

                /* 继续请求 */
                one_byte = YMODEM_CODE_REQ;
                ymodem->write((void *)&one_byte, 1);
                DEBUG("[YMODEM]: SEND REQ\n");
                ymodem->timestart = ymodem->time_msec();
                ymodem->stage = YMODEM_STAGE_TRANSMITTING;
            }
            else {
                /* 删除已经处理的数据 */
                packet_discard(ymodem, discard_len);
            }
        }
        break;
    case YMODEM_STAGE_TRANSMITTING:
        /* 读取数据 */
        ymodem->buffer[ymodem->rd_len] = one_byte;
        ymodem->rd_len += 1;
        len = ymodem->read(ymodem->buffer + ymodem->rd_len, PACKET_OVERHEAD + PACKET_1K_SIZE - ymodem->rd_len);
        ymodem->rd_len += len;

        code = packet_parase(ymodem, &discard_len);
        if (code < 0) {
            DEBUG("[YMODEM]: DISCARD: %d Bytes\n", discard_len);

            /* 删除已经处理的数据 */
            packet_discard(ymodem, discard_len);
        }
        else if (code > 0) {
            if (code == YMODEM_CODE_SOH || code == YMODEM_CODE_STX) {
                DEBUG("[YMODEM]: packet size: %d\n", packet_size(code));
                /* 处理数据 */
                if (ymodem->data_packet_cb) {
                    ret = ymodem->data_packet_cb(&ymodem->buffer[PACKET_HEADER], packet_size(code), ymodem);
                    if (ret < 0) {
                         goto EXIT;
                    }
                }

                /* 删除已经处理的数据 */
                packet_discard(ymodem, discard_len);

                one_byte = YMODEM_CODE_ACK;
                ymodem->write((void *)&one_byte, 1);
                DEBUG("[YMODEM]: SEND ACK\n");
                ymodem->timestart = ymodem->time_msec();
            }
            else if (code == YMODEM_CODE_CAN) {
                DEBUG("[YMODEM]: CANCEL\n");
                if (ymodem->end_packet_cb) {
                    ret = ymodem->end_packet_cb(NULL, 0, ymodem);
                    if (ret < 0) {
                         goto EXIT;
                    }
                }
                ret = -EHOSTDOWN;
                goto EXIT;
            }
            else if (code == YMODEM_CODE_EOT) {
                /* 删除已经处理的数据 */
                packet_discard(ymodem, discard_len);

                one_byte = YMODEM_CODE_NAK;
                ymodem->write((void *)&one_byte, 1);
                DEBUG("[YMODEM]: SEND NAK\n");
                ymodem->timestart = ymodem->time_msec();
                ymodem->stage = YMODEM_STAGE_FINISHING;
            }
            else {
                /* 删除已经处理的数据 */
                packet_discard(ymodem, discard_len);
            }
        }
        break;
    case YMODEM_STAGE_FINISHING:
        /* 读取数据 */
        ymodem->buffer[ymodem->rd_len] = one_byte;
        ymodem->rd_len += 1;
        len = ymodem->read(ymodem->buffer + ymodem->rd_len, PACKET_OVERHEAD + PACKET_1K_SIZE - ymodem->rd_len);
        ymodem->rd_len += len;

        code = packet_parase(ymodem, &discard_len);
        if (code < 0) {
            DEBUG("[YMODEM]: DISCARD: %d Bytes\n", discard_len);

            /* 删除已经处理的数据 */
            packet_discard(ymodem, discard_len);
        }
        else if (code > 0) {
            if (code == YMODEM_CODE_EOT) {
                /* 删除已经处理的数据 */
                packet_discard(ymodem, discard_len);

                one_byte = YMODEM_CODE_ACK;
                ymodem->write((void *)&one_byte, 1);
                DEBUG("[YMODEM]: SEND ACK\n");

                one_byte = YMODEM_CODE_REQ;
                ymodem->write((void *)&one_byte, 1);
                DEBUG("[YMODEM]: SEND REQ\n");

                ymodem->timestart = ymodem->time_msec();
                ymodem->stage = YMODEM_STAGE_FINISHED;
            }
            else {
                /* 删除已经处理的数据 */
                packet_discard(ymodem, discard_len);
            }
        }
        break;
    case YMODEM_STAGE_FINISHED:
        /* 读取数据 */
        ymodem->buffer[ymodem->rd_len] = one_byte;
        ymodem->rd_len += 1;
        len = ymodem->read(ymodem->buffer + ymodem->rd_len, PACKET_OVERHEAD + PACKET_1K_SIZE - ymodem->rd_len);
        ymodem->rd_len += len;

        code = packet_parase(ymodem, &discard_len);
        if (code < 0) {
            DEBUG("[YMODEM]: DISCARD: %d Bytes\n", discard_len);

            /* 删除已经处理的数据 */
            packet_discard(ymodem, discard_len);
        }
        else if (code > 0) {
            if (code == YMODEM_CODE_SOH || code == YMODEM_CODE_STX) {
                if (ymodem->buffer[PACKET_HEADER] == 0x00) {
                    /* 传输结束 */
                    one_byte = YMODEM_CODE_ACK;
                    ymodem->write((void *)&one_byte, 1);
                    DEBUG("[YMODEM]: SEND ACK\n");

                    DEBUG("[YMODEM]: SUCCESS!\n");

                    /* 收尾处理 */
                    if (ymodem->end_packet_cb) {
                        ret = ymodem->end_packet_cb(&ymodem->buffer[PACKET_HEADER], packet_size(code), ymodem);
                        if (ret < 0) {
                             goto EXIT;
                        }
                    }

                    /* 删除已经处理的数据 */
                    packet_discard(ymodem, discard_len);

                    ymodem->rd_len = 0;
                    ymodem->stage = YMODEM_STAGE_NONE;

                    return 0;
                }
                else {
                    /* 握手成功 */
                    one_byte = YMODEM_CODE_ACK;
                    ymodem->write((void *)&one_byte, 1);
                    DEBUG("[YMODEM]: SEND ACK\n");

                    DEBUG("[YMODEM]: CONTINUE\n");

                    /* 收尾处理 */
                    if (ymodem->end_packet_cb) {
                        ret = ymodem->end_packet_cb(&ymodem->buffer[PACKET_HEADER], packet_size(code), ymodem);
                        if (ret < 0) {
                             goto EXIT;
                        }
                    }

                    /* 保存文件名字 */
                    memset(ymodem->file_name, '\0', FILE_NAME_LENGTH);
                    strncpy(ymodem->file_name, (const char *)&ymodem->buffer[PACKET_HEADER], FILE_NAME_LENGTH - 1);

                    /* 保存文件大小 */
                    file_size = (char *)&ymodem->buffer[PACKET_HEADER + strlen((const char *)&ymodem->buffer[PACKET_HEADER]) + 1];
                    ymodem->file_size = str_to_u32(file_size);

                    DEBUG("[YMODEM]: file name: %s, size: %d\n", ymodem->file_name, ymodem->file_size);

                    /* 处理数据 */
                    if (ymodem->begin_packet_cb) {
                        ret = ymodem->begin_packet_cb(&ymodem->buffer[PACKET_HEADER], packet_size(code), ymodem);
                        if (ret < 0) {
                             goto EXIT;
                        }
                    }

                    /* 删除已经处理的数据 */
                    packet_discard(ymodem, discard_len);

                    /* 继续请求 */
                    one_byte = YMODEM_CODE_REQ;
                    ymodem->write((void *)&one_byte, 1);
                    DEBUG("[YMODEM]: SEND REQ\n");
                    ymodem->timestart = ymodem->time_msec();
                    ymodem->stage = YMODEM_STAGE_TRANSMITTING;
                }
            }
            else {
                /* 删除已经处理的数据 */
                packet_discard(ymodem, discard_len);
            }
        }
        break;
    default:
        ret = -EACCES;
        goto EXIT;
        break;
    };

    return -EBUSY;

EXIT:
    one_byte = YMODEM_CODE_CAN;
    ymodem->write((void *)&one_byte, 1);
    DEBUG("[YMODEM]: SEND CAN\n");

    ymodem->rd_len = 0;
    ymodem->stage = YMODEM_STAGE_NONE;

    return ret;
}


int ymodem_send_process(struct ymodem *ymodem)
{
    int ret;
    unsigned char one_byte = 0;

    unsigned char sta, seq, inv;
    unsigned short crc;

    if (NULL == ymodem || NULL == ymodem->read || NULL == ymodem->write || NULL == ymodem->time_msec) {
        return -EINVAL;
    }

    /* 没有收到数据，且进入流程，且接收超时，则传输失败 */
    if (0 >= ymodem->read(&one_byte, 1)) {
        if (ymodem->stage == YMODEM_STAGE_NONE) {
            /* 初始时间为0，则更新时间 */
            if (ymodem->timestart == 0) {
                ymodem->timestart = ymodem->time_msec();
            }

            /* 等待第1个REQ，直到超时 */
            if (ymodem->time_msec() >= ymodem->timestart + ymodem->timeout * 100) {
                /* 已超时，超时失败 */
                DEBUG("[YMODEM]: TIMEOUT REQUEST\n");

                ymodem->stage = YMODEM_STAGE_NONE;
                ymodem->timestart = 0;
                return -ETIMEDOUT;
            }
            else {
                /* 未超时，继续等待 */
                return -EBUSY;
            }
        }
        else if (ymodem->stage == YMODEM_STAGE_ESTABLISHED) {
            /* 等待第2个REQ，直到超时 */
            if (ymodem->time_msec() >= ymodem->timestart + ymodem->timeout * 100) {
                /* 已超时，超时失败 */
                DEBUG("[YMODEM]: TIMEOUT REQUEST\n");
                ret = -ETIMEDOUT;
                goto EXIT;
            }
            else {
                /* 未超时，继续等待 */
                return -EBUSY;
            }
        }
        else {
            if (ymodem->time_msec() >= ymodem->timestart + ymodem->timeout) {
                /* 已超时，超时失败 */
                DEBUG("[YMODEM]: TIMEOUT RESPONE\n");
                ret = -ETIMEDOUT;
                goto EXIT;
            }
            else {
                /* 未超时，继续等待 */
                return -EBUSY;
            }
        }
    }
    /* 已经收到数据，则更新起始时间 */
    else {
        ymodem->timestart = ymodem->time_msec();
        /* 继续往下跑 */
    }

    switch (ymodem->stage) {
    case YMODEM_STAGE_NONE:
        if (one_byte != YMODEM_CODE_REQ) {
            /* 空闲状态，继续接收数据 */
            break;
        }

        /* 检查缓存空间 */
        if (ymodem->buffer == NULL || (ymodem->rd_len != PACKET_SIZE && ymodem->rd_len != PACKET_1K_SIZE)) {
            DEBUG("[YMODEM]: NOBUFFER\n");
            ret = -ENOMEM;
            goto EXIT;
        }

        /* 开始回调 */
        if (ymodem->begin_packet_cb) {
            ret = ymodem->begin_packet_cb(ymodem->buffer, ymodem->rd_len, ymodem);
            if (ret < 0) {
                goto EXIT;
            }
        }

        /* 发送数据 */
        ymodem->sn_len = 0;
        ymodem->sn_seq = 0x00;
        sta = (ymodem->rd_len == PACKET_SIZE)?YMODEM_CODE_SOH:YMODEM_CODE_STX;
        seq = ymodem->sn_seq;
        inv = ~ymodem->sn_seq;
        crc = stdlib_get_crc16_xmodem(ymodem->buffer, ymodem->rd_len);
        ymodem->write((void *)&sta, 1);
        ymodem->write((void *)&seq, 1);
        ymodem->write((void *)&inv, 1);
        ymodem->write(ymodem->buffer + 0, (ymodem->rd_len / 2));
        ymodem->write(ymodem->buffer + (ymodem->rd_len / 2), ymodem->rd_len - (ymodem->rd_len / 2));
        ymodem->write((unsigned char *)&crc + 1, 1);
        ymodem->write((unsigned char *)&crc + 0, 1);

        ymodem->timestart = ymodem->time_msec();
        ymodem->stage = YMODEM_STAGE_ESTABLISHING;

        DEBUG("[YMODEM]: SEND HEAD\n");
        break;
    case YMODEM_STAGE_ESTABLISHING:
        if (one_byte == YMODEM_CODE_CAN) {
            ret = -EHOSTDOWN;
            goto EXIT;
        }
        else if (one_byte == YMODEM_CODE_ACK) {
            ymodem->timestart = ymodem->time_msec();
            ymodem->stage = YMODEM_STAGE_ESTABLISHED;
        }
        break;
    case YMODEM_STAGE_ESTABLISHED:
        if (one_byte == YMODEM_CODE_CAN) {
            ret = -EHOSTDOWN;
            goto EXIT;
        }
        else if (one_byte == YMODEM_CODE_REQ) {
            if (ymodem->sn_len >= ymodem->file_size) {

                /* 结束回调 */
                if (ymodem->end_packet_cb) {
                    ret = ymodem->end_packet_cb(ymodem->buffer, ymodem->rd_len, ymodem);
                    if (ret < 0) {
                        goto EXIT;
                    }
                }

                if (ymodem->buffer[0] == 0x00) {
                    /* 传输结束 */
                    ymodem->sn_seq = 0x00;
                    sta = (ymodem->rd_len == PACKET_SIZE)?YMODEM_CODE_SOH:YMODEM_CODE_STX;
                    seq = ymodem->sn_seq;
                    inv = ~ymodem->sn_seq;
                    crc = stdlib_get_crc16_xmodem(ymodem->buffer, ymodem->rd_len);
                    ymodem->write((void *)&sta, 1);
                    ymodem->write((void *)&seq, 1);
                    ymodem->write((void *)&inv, 1);
                    ymodem->write(ymodem->buffer + 0, (ymodem->rd_len / 2));
                    ymodem->write(ymodem->buffer + (ymodem->rd_len / 2), ymodem->rd_len - (ymodem->rd_len / 2));
                    ymodem->write((unsigned char *)&crc + 1, 1);
                    ymodem->write((unsigned char *)&crc + 0, 1);

                    /* 发送一个文件成功 */
                    ymodem->stage = YMODEM_STAGE_NONE;
                    ymodem->timestart = 0;

                    DEBUG("[YMODEM]: SEND TAIL\n");
                    DEBUG("[YMODEM]: SUCCESS!\n");
                    return 0;
                }
                else {
                    /* 发送数据 */
                    ymodem->sn_len = 0;
                    ymodem->sn_seq = 0x00;
                    sta = (ymodem->rd_len == PACKET_SIZE)?YMODEM_CODE_SOH:YMODEM_CODE_STX;
                    seq = ymodem->sn_seq;
                    inv = ~ymodem->sn_seq;
                    crc = stdlib_get_crc16_xmodem(ymodem->buffer, ymodem->rd_len);
                    ymodem->write((void *)&sta, 1);
                    ymodem->write((void *)&seq, 1);
                    ymodem->write((void *)&inv, 1);
                    ymodem->write(ymodem->buffer + 0, (ymodem->rd_len / 2));
                    ymodem->write(ymodem->buffer + (ymodem->rd_len / 2), ymodem->rd_len - (ymodem->rd_len / 2));
                    ymodem->write((unsigned char *)&crc + 1, 1);
                    ymodem->write((unsigned char *)&crc + 0, 1);

                    ymodem->timestart = ymodem->time_msec();
                    ymodem->stage = YMODEM_STAGE_ESTABLISHING;

                    DEBUG("[YMODEM]: SEND HEAD\n");
                    DEBUG("[YMODEM]: CONTINUE!\n");
                    break;
                }
            }

            /* 发送第一包数据 */
            if (ymodem->data_packet_cb) {
                ret = ymodem->data_packet_cb(ymodem->buffer, ymodem->rd_len, ymodem);
                if (ret < 0) {
                    goto EXIT;
                }
            }

            /* 发送数据 */
            ymodem->sn_seq = ymodem->sn_seq + 1;
            sta = (ymodem->rd_len == PACKET_SIZE)?YMODEM_CODE_SOH:YMODEM_CODE_STX;
            seq = ymodem->sn_seq;
            inv = ~ymodem->sn_seq;
            crc = stdlib_get_crc16_xmodem(ymodem->buffer, ymodem->rd_len);
            ymodem->write((void *)&sta, 1);
            ymodem->write((void *)&seq, 1);
            ymodem->write((void *)&inv, 1);
            ymodem->write(ymodem->buffer + 0, (ymodem->rd_len / 2));
            ymodem->write(ymodem->buffer + (ymodem->rd_len / 2), ymodem->rd_len - (ymodem->rd_len / 2));
            ymodem->write((unsigned char *)&crc + 1, 1);
            ymodem->write((unsigned char *)&crc + 0, 1);
            ymodem->sn_len += ymodem->rd_len;

            ymodem->timestart = ymodem->time_msec();
            ymodem->stage = YMODEM_STAGE_TRANSMITTING;

            DEBUG("[YMODEM]: SEND DATA\n");
        }
        break;
    case YMODEM_STAGE_TRANSMITTING:
        if (one_byte == YMODEM_CODE_CAN){
            ret = -EHOSTDOWN;
            goto EXIT;
        }
        else if (one_byte == YMODEM_CODE_ACK) {
            /* 检查发送数据是否完成 */
            if (ymodem->sn_len >= ymodem->file_size) {
                one_byte = YMODEM_CODE_EOT;
                ymodem->write((void *)&one_byte, 1);
                ymodem->timestart = ymodem->time_msec();
                ymodem->stage = YMODEM_STAGE_FINISHING;

                DEBUG("[YMODEM]: SEND EOT\n");
                break;
            }

            /* 发送下一包数据 */
            if (ymodem->data_packet_cb) {
                ret = ymodem->data_packet_cb(ymodem->buffer, ymodem->rd_len, ymodem);
                if (ret < 0) {
                    goto EXIT;
                }
            }

            /* 发送数据 */
            ymodem->sn_seq = ymodem->sn_seq + 1;
            sta = (ymodem->rd_len == PACKET_SIZE)?YMODEM_CODE_SOH:YMODEM_CODE_STX;
            seq = ymodem->sn_seq;
            inv = ~ymodem->sn_seq;
            crc = stdlib_get_crc16_xmodem(ymodem->buffer, ymodem->rd_len);
            ymodem->write((void *)&sta, 1);
            ymodem->write((void *)&seq, 1);
            ymodem->write((void *)&inv, 1);
            ymodem->write(ymodem->buffer + 0, (ymodem->rd_len / 2));
            ymodem->write(ymodem->buffer + (ymodem->rd_len / 2), ymodem->rd_len - (ymodem->rd_len / 2));
            ymodem->write((unsigned char *)&crc + 1, 1);
            ymodem->write((unsigned char *)&crc + 0, 1);
            ymodem->sn_len += ymodem->rd_len;

            ymodem->timestart = ymodem->time_msec();
            ymodem->stage = YMODEM_STAGE_TRANSMITTING;

            DEBUG("[YMODEM]: SEND DATA\n");
        }
        break;
    case YMODEM_STAGE_FINISHING:
        if (one_byte == YMODEM_CODE_CAN) {
            ret = -EHOSTDOWN;
            goto EXIT;
        }
        else if (one_byte == YMODEM_CODE_NAK) {
            one_byte = YMODEM_CODE_EOT;
            ymodem->write((void *)&one_byte, 1);

            ymodem->timestart = ymodem->time_msec();
            ymodem->stage = YMODEM_STAGE_FINISHED;

            DEBUG("[YMODEM]: SEND EOT\n");
        }
        break;
    case YMODEM_STAGE_FINISHED:
        if (one_byte == YMODEM_CODE_CAN) {
            ret = -EHOSTDOWN;
            goto EXIT;
        }
        else if (one_byte == YMODEM_CODE_ACK) {
            ymodem->timestart = ymodem->time_msec();
            ymodem->stage = YMODEM_STAGE_ESTABLISHED;
        }
        break;
    default:
        ret = -EACCES;
        goto EXIT;
        break;
    };

    return -EBUSY;

EXIT:
    one_byte = YMODEM_CODE_CAN;
    ymodem->write((void *)&one_byte, 1);
    ymodem->stage = YMODEM_STAGE_NONE;
    ymodem->timestart = 0;

    DEBUG("[YMODEM]: SEND CAN\n");
    return ret;
}

int ymodem_process(struct ymodem *ymodem)
{
    if (ymodem->mode == YMODEM_MODE_RECV) {
        return ymodem_recv_process(ymodem);
    }
    else if(ymodem->mode == YMODEM_MODE_SEND) {
        return ymodem_send_process(ymodem);
    }
    else {
        return -EPERM;
    }
}


/* 计算包数据段大小 */
static int packet_size(unsigned char code)
{
    switch (code) {
    case YMODEM_CODE_SOH:
        return PACKET_SIZE;
        break;
    case YMODEM_CODE_STX:
         return PACKET_1K_SIZE;
        break;
    case YMODEM_CODE_EOT:
    case YMODEM_CODE_ACK:
    case YMODEM_CODE_NAK:
    case YMODEM_CODE_CAN:
    case YMODEM_CODE_REQ:
        return 0;
        break;
    default:
        return 0;
        break;
    }
}

/* -1表示解析失败，0表示继续接收数据，大于0表示解析成功 */
static int  packet_parase(struct ymodem *ymodem, unsigned int *discard_len)
{
    *discard_len = 0;
    unsigned char *packet = ymodem->buffer;
    unsigned int   length = ymodem->rd_len;

    unsigned char code = packet[PACKET_START_INDEX];

    switch (code) {
    case YMODEM_CODE_SOH:
        if (length >= PACKET_OVERHEAD + PACKET_SIZE) {
            if (packet[PACKET_SEQNO_INDEX] != ((packet[PACKET_SEQNO_COMP_INDEX] ^ 0xff) & 0xff)) {
                *discard_len = PACKET_HEADER;
                DEBUG("[YMODEM]: SEQ ERROR\n");
                return -1;
            }

            if (stdlib_get_crc16_xmodem(packet + PACKET_HEADER, PACKET_SIZE + PACKET_TRAILER) != 0) {
                *discard_len = PACKET_OVERHEAD + PACKET_SIZE;
                DEBUG("[YMODEM]: CRC ERROR\n");
                return -1;
            }

            DEBUG("[YMODEM]: RECV SOH\n");
            *discard_len = PACKET_OVERHEAD + PACKET_SIZE;
            return YMODEM_CODE_SOH;
        }
        break;
    case YMODEM_CODE_STX:
        if (length >= PACKET_OVERHEAD + PACKET_1K_SIZE) {
            if (packet[PACKET_SEQNO_INDEX] != ((packet[PACKET_SEQNO_COMP_INDEX] ^ 0xff) & 0xff)) {
                *discard_len = PACKET_HEADER;
                DEBUG("[YMODEM]: SEQ ERROR\n");
                return -1;
            }

            if (stdlib_get_crc16_xmodem(packet + PACKET_HEADER, PACKET_1K_SIZE + PACKET_TRAILER) != 0) {
                *discard_len = PACKET_OVERHEAD + PACKET_1K_SIZE;
                DEBUG("[YMODEM]: CRC ERROR\n");
                return -1;
            }

            DEBUG("[YMODEM]: RECV STX\n");
            *discard_len = PACKET_OVERHEAD + PACKET_1K_SIZE;
            return YMODEM_CODE_STX;
        }
        break;
    case YMODEM_CODE_EOT:
        DEBUG("[YMODEM]: RECV EOT\n");
        *discard_len = 1;
        return YMODEM_CODE_EOT;
        break;
    case YMODEM_CODE_ACK:
        DEBUG("[YMODEM]: RECV ACK\n");
        *discard_len = 1;
        return YMODEM_CODE_ACK;
        break;
    case YMODEM_CODE_NAK:
        DEBUG("[YMODEM]: RECV NAK\n");
        *discard_len = 1;
        return YMODEM_CODE_NAK;
        break;
    case YMODEM_CODE_CAN:
        DEBUG("[YMODEM]: RECV CAN\n");
        *discard_len = 1;
        return YMODEM_CODE_CAN;
        break;
    case YMODEM_CODE_REQ:
        DEBUG("[YMODEM]: RECV REQ\n");
        *discard_len = 1;
        return YMODEM_CODE_REQ;
        break;
    default:
        DEBUG("[YMODEM]: CODE UNKNOW\n");
        *discard_len = 1;
        return -1;
        break;
    }

    /* 继续解析 */
    return 0;
}

/* 丢弃前面discard_len字节数据 */
static void packet_discard(struct ymodem *ymodem, unsigned int discard_len)
{
    /* 删除已经处理的数据 */
    for (int i = 0; i < (int)(ymodem->rd_len - discard_len); i++) {
        ymodem->buffer[i] = ymodem->buffer[i + discard_len];
    }
    ymodem->rd_len -= discard_len;
}

/* 字符串转U32 */
static unsigned int str_to_u32(const char* str)
{
    const char *s = str;
    unsigned int acc;
    int c;

    /* strip leading spaces if any */
    do {
        c = *s++;
    } while (c == ' ');

    for (acc = 0; (c >= '0') && (c <= '9'); c = *s++) {
        c -= '0';
        acc *= 10;
        acc += c;
    }

    return acc;
}


/* U32转字符串 */
static const char *u32_to_str(unsigned int val)
{
        /* Maximum number of decimal digits in u32 is 10 */
        static char num_str[11];
        int  pos = 10;
        num_str[10] = 0;

        if (val == 0) {
                /* If already zero then just return zero */
                return "0";
        }

        while ((val != 0) && (pos > 0)) {
                num_str[--pos] = (val % 10) + '0';
                val /= 10;
        }

        return &num_str[pos];
}


/* U32转字符串 */
const char *ymodem_u32_to_str(unsigned int val)
{
    return u32_to_str(val);
}
